﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Xml;
using System.Runtime.Serialization.Formatters;
using System.Runtime.Serialization.Json;
using System.Text;
using System.Xml.Linq;
using System.Net.Http;
using System.IO;
using System.Threading.Tasks;
using System.Net;
using System.Web.Script.Serialization;

namespace WeSpot.Models
{
    public static class ARLearnUtils
    {
        /// <summary>
        /// Convert json string to XmlDocument
        /// </summary>
        /// <param name="json"></param>
        /// <returns></returns>
        public static XmlDocument JsonToXML(string json)
        {
            XmlDocument doc = new XmlDocument();

            using (var reader = JsonReaderWriterFactory.CreateJsonReader(Encoding.UTF8.GetBytes(json), XmlDictionaryReaderQuotas.Max))
            {
                XElement xml = XElement.Load(reader);
                doc.LoadXml(xml.ToString());
            }

            return doc;
        }

        /// <summary>
        /// Get provider code
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public static string GetProviderDescription(int codeProvider)
        {
            switch (codeProvider)
            {
                case 1:
                    return "Facebook";
                case 2:
                    return "Google";
                case 3:
                    return "Linkedin";
                case 4:
                    return "Twitter";
                case 5:
                    return "WeSpot";
            }

            return "unknown";
        }


        /// <summary>
        /// Get provider code
        /// </summary>
        /// <param name="provider"></param>
        /// <returns></returns>
        public static int GetProviderCode(string provider)
        {
            switch (provider.ToLower())
            {
                case "facebook":
                    return 1;
                case "google":
                    return 2;
                case "linkedid":
                    return 3;
                case "twitter":
                    return 4;
                case "wespot":
                    return 5;
            }

            return 0;
        }

        /// <summary>
        /// Get ARLearn material
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="provider"></param>
        /// <param name="authCode"></param>
        /// <returns></returns>
        private static string GetARLearn(string uri, string provider, string authCode)
        {
            int providerCode = GetProviderCode(provider);

            if (providerCode == 0)
            {
                //raise exception !!!
            }

            // build the request url with the tableName appended to the end.
            WebRequest request = WebRequest.Create(uri);

            // use the GET method.
            request.Method = "GET";
            request.Headers["Authorization"] = "onBehalfOf:" + Properties.Settings.Default.ARLearnAccessToken + ":" + providerCode + ":" + authCode;

            // create a web response
            WebResponse response = request.GetResponse();

            // create a data stream.
            Stream dataStream = response.GetResponseStream();

            // create a stream reader.
            StreamReader reader = new StreamReader(dataStream);

            // read the content into a string
            string ret = reader.ReadToEnd();

            reader.Close();
            dataStream.Close();
            response.Close();

            return ret;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="uri"></param>
        /// <param name="json"></param>
        /// <param name="provider"></param>
        /// <param name="authCode"></param>
        /// <returns></returns>
        private static string PostARLearn(string uri, string json, string provider, string authCode)
        {
            int providerCode = GetProviderCode(provider);

            if (providerCode == 0)
            {
                //raise exception !!!
            }

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
            request.ContentType = "application/json";
            request.Method = "POST";
            request.Headers["Authorization"] = "onBehalfOf:" + Properties.Settings.Default.ARLearnAccessToken + ":" + providerCode + ":" + authCode;

            using (var streamWriter = new StreamWriter(request.GetRequestStream()))
            {
                streamWriter.Write(json);
            }

            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            
            using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
            {
                return streamReader.ReadToEnd();
            }
        }

        /// <summary>
        /// This method enables retrieving all responses for a runId
        /// </summary>
        /// <param name="runId"></param>
        /// <param name="fromDate"></param>
        /// <param name="provider"></param>
        /// <param name="oauth"></param>
        /// <returns></returns>
        public static string GetRunResponses(string runId, DateTime fromDate, string provider, string oauth)
        {
            long millis = (long)(fromDate.ToUniversalTime() - new DateTime (1970, 1, 1)).TotalMilliseconds;

            string uri = @"" + Properties.Settings.Default.ARLearnUrl + "response/runId/" + runId + "?from=" + millis + "";

            bool loop = true;
            string responses = GetARLearn(uri, provider, oauth);

            JavaScriptSerializer jss = new JavaScriptSerializer();
            ARLearnJSonModels.Rootobject root = jss.Deserialize<ARLearnJSonModels.Rootobject>(responses);

            if (root.resumptionToken == null || root.resumptionToken.Equals(string.Empty))
            {
                loop = false;
            }

            string resToken = root.resumptionToken;

            while (loop)
            {
                responses = GetRunResponses(runId, resToken, fromDate, provider, oauth);

                ARLearnJSonModels.Rootobject localRoot = jss.Deserialize<ARLearnJSonModels.Rootobject>(responses);
                var a=root.responses.Concat(localRoot.responses);
                root.responses = a.ToArray();
                //root.responses = (ARLearnJSonModels.Respons[])root.responses.Concat<ARLearnJSonModels.Respons>(localRoot.responses);

                if (localRoot.resumptionToken==null)
                {
                    loop = false;
                }

                resToken = localRoot.resumptionToken;
            }

            return jss.Serialize(root);
        }

        /// <summary>
        /// For performance reasons not all responses are returned.
        /// Rather you must iterate through the list of results using the same timestamps provided in the original request.
        /// Download the next batch of responses with the following request. 
        /// The parameter resumptionToken MUST be equal to the resumptionToken that was returned by the server in the first batch of results.
        /// </summary>
        /// <param name="runId"></param>
        /// <param name="resumptionToken"></param>
        /// <param name="fromDate"></param>
        /// <param name="provider"></param>
        /// <param name="oauth"></param>
        /// <returns></returns>
        public static string GetRunResponses(string runId, string resumptionToken, DateTime fromDate, string provider, string oauth)
        {
            long millis = (long)(fromDate.ToUniversalTime() - new DateTime(1970, 1, 1)).TotalMilliseconds;

            string uri = @"" + Properties.Settings.Default.ARLearnUrl + "response/runId/" + runId + "?from=" + millis + "&resumptionToken=" + resumptionToken + "";

            return GetARLearn(uri, provider, oauth);
        }

        /// <summary>
        /// This method enables retrieving all message given a game.
        /// </summary>
        /// <param name="gameId"></param>
        /// <param name="provider"></param>
        /// <param name="oauth"></param>
        /// <returns></returns>
        public static string GetGameGeneralItems(string gameId, string provider, string oauth)
        {
            string uri = @"" + Properties.Settings.Default.ARLearnUrl + "generalItems/gameId/" + gameId + "";

            return GetARLearn(uri, provider, oauth);
        }

        //    string json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(new
        //    {
        //        user = "Foo",
        //        password = "Baz"
        //    });

        /// <summary>
        /// This method creates a new thread. 
        /// </summary>
        /// <param name="runId"></param>
        /// <param name="treadName"></param>
        /// <param name="provider"></param>
        /// <param name="oauth"></param>
        /// <returns></returns>
        public static string PostCreateThread(string runId, string treadName, string provider, string oauth)
        {
            string json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(new
            {
                type = "org.celstec.arlearn2.beans.run.Thread",
                runId = runId,
                name = treadName
            });

            string uri = @"" + Properties.Settings.Default.ARLearnUrl + "messages/thread";

            return PostARLearn(uri, json, provider, oauth);
        }

        /// <summary>
        /// This method retrieves all threads given a run.
        /// </summary>
        /// <param name="runId"></param>
        /// <param name="provider"></param>
        /// <param name="oauth"></param>
        /// <returns></returns>
        public static string GetThreads(string runId, string provider, string oauth)
        {
            string uri = @"" + Properties.Settings.Default.ARLearnUrl + "messages/thread/runId/" + runId + "";

            return GetARLearn(uri, provider, oauth);
        }

        /// <summary>
        /// This method returns the default thread for a run. Every run has a default thread.
        /// </summary>
        /// <param name="runId"></param>
        /// <param name="provider"></param>
        /// <param name="oauth"></param>
        /// <returns></returns>
        public static string GetDefaultThread(string runId, string provider, string oauth)
        {
            string uri = @"" + Properties.Settings.Default.ARLearnUrl + "messages/thread/runId/" + runId + "/default";

            return GetARLearn(uri, provider, oauth);
        }

        /// <summary>
        /// This method retrieves messages for a thread
        /// </summary>
        /// <param name="treadId"></param>
        /// <param name="provider"></param>
        /// <param name="oauth"></param>
        /// <returns></returns>
        public static string GetThreadMessages(string treadId, string provider, string oauth)
        {
            string uri = @"" + Properties.Settings.Default.ARLearnUrl + "messages/threadId/" + treadId + "";

            return GetARLearn(uri, provider, oauth);
        }

        /// <summary>
        /// This method returns the list of threads available within this run.
        /// </summary>
        /// <param name="runId"></param>
        /// <param name="provider"></param>
        /// <param name="oauth"></param>
        /// <returns></returns>
        public static string GetDefaultRunMessages(string runId, string provider, string oauth)
        {
            string uri = @"" + Properties.Settings.Default.ARLearnUrl + "messages/runId/" + runId + "/default";

            return GetARLearn(uri, provider, oauth);
        }

        /// <summary>
        /// New message for the default thread all users
        /// </summary>
        /// <param name="runId"></param>
        /// <param name="subjectString"></param>
        /// <param name="bodyString"></param>
        /// <param name="provider"></param>
        /// <param name="oauth"></param>
        /// <returns></returns>
        public static string PostCreateMessage(string runId, string subjectString, string bodyString, string provider, string oauth)
        {
            string json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(new
            {
                type = "org.celstec.arlearn2.beans.run.Message",
                runId = runId,
                subject = subjectString,
                body = bodyString
            });

            string uri = @"" + Properties.Settings.Default.ARLearnUrl + "messages/message";

            return PostARLearn(uri, json, provider, oauth);
        }

        /// <summary>
        /// Message for a specific user and thread
        /// </summary>
        /// <param name="runId"></param>
        /// <param name="threadIdString"></param>
        /// <param name="subjectString"></param>
        /// <param name="bodyString"></param>
        /// <param name="userId"></param>
        /// <param name="provider"></param>
        /// <param name="oauth"></param>
        /// <returns></returns>
        public static string PostCreateMessage(string runId, string threadIdString, string subjectString, string bodyString, string userId, string provider, string oauth)
        {
            string json = new System.Web.Script.Serialization.JavaScriptSerializer().Serialize(new
            {
                type = "org.celstec.arlearn2.beans.run.Message",
                runId = runId,
                threadId = threadIdString,
                subject = subjectString,
                body = bodyString,
                userIds = new { userId }
            });

            string uri = @"" + Properties.Settings.Default.ARLearnUrl + "messages/message";

            return PostARLearn(uri, json, provider, oauth);
        }
    }
}